const fs = require('fs-extra')
const glob = require('glob')
const path = require('node:path')
const compressing = require('compressing')


/**
 * 获取文件或目录的源信息
 * @param {string|string[]} pathName 绝对路径，支持文件夹、文件、glob通配符
 * @returns {{source: string[], is_dir: boolean, base_dir: string}}
 *  source: 资源文件数组
 *  is_dir: 是否为目录，如果是目录则base_dir就是这个目录路径
 *  base_dir: 匹配到文件的相对根目录，例如匹配 /www/abc/dist/*.js 时，base 为 /www/abc/dist/
 */
function getSourceInfo(pathName) {
	if (Array.isArray(pathName)) {
		// 递归获取所有 source
		let allSources = []
		let allBaseDirs = []
		for (const p of pathName) {
			const res = getSourceInfo(p)
			allSources = allSources.concat(res.source)
			// 只收集有文件的base_dir
			if (res.source.length > 0) {
				allBaseDirs.push(res.base_dir)
			}
		}
		// 计算最小公共父目录
		let base_dir = ''
		if (allBaseDirs.length > 0) {
			const splitDirs = allBaseDirs.map((dir) => path.resolve(dir).split(path.sep))
			let minLen = Math.min(...splitDirs.map((arr) => arr.length))
			let common = []
			for (let i = 0; i < minLen; i++) {
				const seg = splitDirs[0][i]
				if (splitDirs.every((arr) => arr[i] === seg)) {
					common.push(seg)
				} else {
					break
				}
			}
			base_dir = common.length > 0 ? common.join(path.sep) : ''
		}
		return {
			is_dir: false,
			base_dir,
			source: allSources,
		}
	}

	try {
		const stat = fs.statSync(pathName)
		if (stat.isDirectory()) {
			const pattern = pathName.replace(/\\/g, '/') + '/**/*'
			const files = glob.sync(pattern, { nodir: true })
			return { source: files, is_dir: true, base_dir: path.resolve(pathName) }
		}
	} catch (e) {
		// 不是本地目录，继续走 glob
	}

	// 其余情况直接 glob 匹配
	const pattern = pathName.replace(/\\/g, '/')
	const matchedFiles = glob.sync(pattern, { nodir: true })

	// 计算 base_dir
	let base_dir = pattern
	const globIndex = Math.min(
		...['*', '?', '[', '{'].map((s) => {
			const i = pattern.indexOf(s)
			return i === -1 ? pattern.length : i
		})
	)
	base_dir = path.resolve(pattern.substring(0, globIndex))

	// 这里直接用传入的 pathName 相关部分，不做分隔符转换
	if (matchedFiles.length === 0) {
		return { source: [], is_dir: false, base_dir }
	} else {
		return { source: matchedFiles, is_dir: false, base_dir }
	}
}

/**
 * 压缩指定的文件或目录
 * @param {object} sourceInfo 资源信息，同getSourceInfo()的返回对象
 * @param {string} zipName 压缩文件路径和文件名
 * @return {Promise<void>} 返回一个Promise，表示压缩完成
 */
async function zipSource(sourceInfo, zipName) {
	const zipFileName = path.resolve(zipName) // zip文件目录
	fs.ensureDirSync(path.dirname(zipFileName)) // 确保目录存在

	if (sourceInfo.is_dir) {
		return await compressing.zip.compressDir(sourceInfo.base_dir, zipFileName, {
			ignoreBase: true,
		})
	} else {
		const zip = new compressing.zip.Stream()

		for (const filePath of sourceInfo.source) {
			const stat = fs.statSync(filePath)
			if (stat.isFile()) {
				// 保留相对base_dir的完整目录结构
				const relativePath = path.relative(sourceInfo.base_dir, filePath)
				zip.addEntry(filePath, { relativePath })
			}
		}

		return await new Promise((resolve, reject) => {
			const writeStream = fs.createWriteStream(zipFileName)
			zip.pipe(writeStream)
			writeStream.on('close', resolve)
			writeStream.on('error', reject)
			zip.on('error', reject)
		})
	}
}

module.exports = {
	getSourceInfo,
	zipSource,
}